Практическое задание 4. «Визуальный анализ данных»¶

4.1. Работа с датасетом "house price"¶

In [ ]:
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

4.1.1 Скачать данные по ссылке¶

In [ ]:
df = pd.read_csv('kc-house-data.csv')
In [ ]:
df.head()
Out[ ]:
id date price bedrooms bathrooms sqft_living sqft_lot floors waterfront view ... grade sqft_above sqft_basement yr_built yr_renovated zipcode lat long sqft_living15 sqft_lot15
0 7129300520 20141013T000000 221900.0 3 1.00 1180 5650 1.0 0 0 ... 7 1180 0 1955 0 98178 47.5112 -122.257 1340 5650
1 6414100192 20141209T000000 538000.0 3 2.25 2570 7242 2.0 0 0 ... 7 2170 400 1951 1991 98125 47.7210 -122.319 1690 7639
2 5631500400 20150225T000000 180000.0 2 1.00 770 10000 1.0 0 0 ... 6 770 0 1933 0 98028 47.7379 -122.233 2720 8062
3 2487200875 20141209T000000 604000.0 4 3.00 1960 5000 1.0 0 0 ... 7 1050 910 1965 0 98136 47.5208 -122.393 1360 5000
4 1954400510 20150218T000000 510000.0 3 2.00 1680 8080 1.0 0 0 ... 8 1680 0 1987 0 98074 47.6168 -122.045 1800 7503

5 rows × 21 columns

4.1.2 Изучите стоимости недвижимости¶

  • Постройте график
  • Назовите график
  • Сделайте именование оси x и оси y
  • Сделайте выводы
In [ ]:
df.describe()
Out[ ]:
id price bedrooms bathrooms sqft_living sqft_lot floors waterfront view condition grade sqft_above sqft_basement yr_built yr_renovated zipcode lat long sqft_living15 sqft_lot15
count 2.161300e+04 2.161300e+04 21613.000000 21613.000000 21613.000000 2.161300e+04 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000 21613.000000
mean 4.580302e+09 5.400881e+05 3.370842 2.114757 2079.899736 1.510697e+04 1.494309 0.007542 0.234303 3.409430 7.656873 1788.390691 291.509045 1971.005136 84.402258 98077.939805 47.560053 -122.213896 1986.552492 12768.455652
std 2.876566e+09 3.671272e+05 0.930062 0.770163 918.440897 4.142051e+04 0.539989 0.086517 0.766318 0.650743 1.175459 828.090978 442.575043 29.373411 401.679240 53.505026 0.138564 0.140828 685.391304 27304.179631
min 1.000102e+06 7.500000e+04 0.000000 0.000000 290.000000 5.200000e+02 1.000000 0.000000 0.000000 1.000000 1.000000 290.000000 0.000000 1900.000000 0.000000 98001.000000 47.155900 -122.519000 399.000000 651.000000
25% 2.123049e+09 3.219500e+05 3.000000 1.750000 1427.000000 5.040000e+03 1.000000 0.000000 0.000000 3.000000 7.000000 1190.000000 0.000000 1951.000000 0.000000 98033.000000 47.471000 -122.328000 1490.000000 5100.000000
50% 3.904930e+09 4.500000e+05 3.000000 2.250000 1910.000000 7.618000e+03 1.500000 0.000000 0.000000 3.000000 7.000000 1560.000000 0.000000 1975.000000 0.000000 98065.000000 47.571800 -122.230000 1840.000000 7620.000000
75% 7.308900e+09 6.450000e+05 4.000000 2.500000 2550.000000 1.068800e+04 2.000000 0.000000 0.000000 4.000000 8.000000 2210.000000 560.000000 1997.000000 0.000000 98118.000000 47.678000 -122.125000 2360.000000 10083.000000
max 9.900000e+09 7.700000e+06 33.000000 8.000000 13540.000000 1.651359e+06 3.500000 1.000000 4.000000 5.000000 13.000000 9410.000000 4820.000000 2015.000000 2015.000000 98199.000000 47.777600 -121.315000 6210.000000 871200.000000
In [ ]:
plt.hist(df['price'], bins=100)
plt.title('Стоимость недвижимости')
plt.xlabel('Стоимость')
plt.ylabel('Количество');
In [ ]:
plt.figure(figsize=(6,4))
plt.boxplot(df['price'])
plt.title('Cтоимость недвижимости')
plt.ylabel('Cтоимость');

Вывод: Большая часть домов находится в диапозоне стоимости от 0,2x10^6 до 1,1х10^6

4.1.3 Изучите распределение квадратуры жилой площади¶

In [ ]:
plt.figure(figsize=(6,4))
plt.hist(df['sqft_living'], bins=100)
plt.title('Распределение жилой площади')
plt.xlabel('Жилая площадь')
plt.ylabel('Количество');
In [ ]:
plt.figure(figsize=(6,4))
plt.boxplot(df['sqft_living'])
plt.title('Жилая площадь')
plt.ylabel('Жилая площадь');

Вывод: Большая часть домов находятся в диапозоне от 400 до 4000 кв. фута по жилой площади

4.1.4 Изучите распределение года постройки¶

In [ ]:
plt.figure(figsize=(6,4))
plt.hist(df['yr_built'], bins=10)
plt.title('Распределение по году постройки')
plt.xlabel('Год постройки')
plt.ylabel('Количество');
In [ ]:
plt.figure(figsize=(6,4))
plt.boxplot(df['yr_built'])
plt.title('Распределение по году постройки')
plt.ylabel('Год постройки');

Выводы: Большая часть домов построено с 1950 по 2000 гг. Есть большой пик новых домов построенных в середине 2000

4.2. Работа с датасетом "house price"¶

4.2.1 Изучите распределение домов от наличия вида на набережную¶

In [ ]:
dataFGW = df['waterfront'].value_counts()
dataFGW
Out[ ]:
waterfront
0    21450
1      163
Name: count, dtype: int64
In [ ]:
plt.pie(dataFGW.values, autopct='%.1f%%', labels=dataFGW.index);
plt.title('Распределение домов по виду на набережную')
Out[ ]:
Text(0.5, 1.0, 'Распределение домов по виду на набережную')

Выводы: Подавляющие большинство домов 99,2% без вида на набережную

4.2.2 Изучите распределение этажей домов¶

In [ ]:
dataFGF = df['floors'].value_counts().reset_index()
dataFGF.head()
Out[ ]:
floors count
0 1.0 10680
1 2.0 8241
2 1.5 1910
3 3.0 613
4 2.5 161
In [ ]:
total = sum(dataFGF['count'])
labelsPie = [f'{n}  {v/total:.2%}' for n,v in zip(dataFGF['floors'], dataFGF['count'])]
labelsPie
plt.pie(dataFGF['count'])
plt.title('Распределение домов по количеству этажей, %')
plt.xlabel("")
plt.legend(labels = labelsPie)
Out[ ]:
<matplotlib.legend.Legend at 0x2584b290850>

Выводы: Большинство домов одно и двух этажной застройки

4.2.3 Изучите распределение состояния домов¶

In [ ]:
dataFGС = df['condition'].value_counts()
dataFGС
Out[ ]:
condition
3    14031
4     5679
5     1701
2      172
1       30
Name: count, dtype: int64
In [ ]:
plt.figure(figsize=(6,4))
plt.bar(dataFGС.index, dataFGС.values)
plt.title('Распределение состояния домов')
plt.xlabel('Состояние')
plt.ylabel('Количество, шт')
Out[ ]:
Text(0, 0.5, 'Количество, шт')

Выводы: Большинство домов c состоянием 3. Домов в плохом состоянии 1 и 2 меньшинство

4.3 Работа с датасетом "house price"¶

4.4.1 Исследуйте, какие характеристики недвижимости влияют на стоимость недвижимости, с применением не менее 5 диаграмм из урока.¶

- Анализ сделайте в формате storytelling: дополнить каждый график письменными выводами и наблюдениями.

Для начала проверим корреляцию характеристик построив матрицу корреляций

In [ ]:
corr_matrix = df.corr(numeric_only=True)
corr_matrix = np.round(corr_matrix, 1)
corr_matrix[np.abs(corr_matrix) < 0.3] = 0
corr_matrix
Out[ ]:
id price bedrooms bathrooms sqft_living sqft_lot floors waterfront view condition grade sqft_above sqft_basement yr_built yr_renovated zipcode lat long sqft_living15 sqft_lot15
id 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
price 0.0 1.0 0.3 0.5 0.7 0.0 0.3 0.3 0.4 0.0 0.7 0.6 0.3 0.0 0.0 0.0 0.3 0.0 0.6 0.0
bedrooms 0.0 0.3 1.0 0.5 0.6 0.0 0.0 0.0 0.0 0.0 0.4 0.5 0.3 0.0 0.0 0.0 0.0 0.0 0.4 0.0
bathrooms 0.0 0.5 0.5 1.0 0.8 0.0 0.5 0.0 0.0 0.0 0.7 0.7 0.3 0.5 0.0 0.0 0.0 0.0 0.6 0.0
sqft_living 0.0 0.7 0.6 0.8 1.0 0.0 0.4 0.0 0.3 0.0 0.8 0.9 0.4 0.3 0.0 0.0 0.0 0.0 0.8 0.0
sqft_lot 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.7
floors 0.0 0.3 0.0 0.5 0.4 0.0 1.0 0.0 0.0 -0.3 0.5 0.5 0.0 0.5 0.0 0.0 0.0 0.0 0.3 0.0
waterfront 0.0 0.3 0.0 0.0 0.0 0.0 0.0 1.0 0.4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
view 0.0 0.4 0.0 0.0 0.3 0.0 0.0 0.4 1.0 0.0 0.3 0.0 0.3 0.0 0.0 0.0 0.0 0.0 0.3 0.0
condition 0.0 0.0 0.0 0.0 0.0 0.0 -0.3 0.0 0.0 1.0 0.0 0.0 0.0 -0.4 0.0 0.0 0.0 0.0 0.0 0.0
grade 0.0 0.7 0.4 0.7 0.8 0.0 0.5 0.0 0.3 0.0 1.0 0.8 0.0 0.4 0.0 0.0 0.0 0.0 0.7 0.0
sqft_above 0.0 0.6 0.5 0.7 0.9 0.0 0.5 0.0 0.0 0.0 0.8 1.0 0.0 0.4 0.0 -0.3 0.0 0.3 0.7 0.0
sqft_basement 0.0 0.3 0.3 0.3 0.4 0.0 0.0 0.0 0.3 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
yr_built 0.0 0.0 0.0 0.5 0.3 0.0 0.5 0.0 0.0 -0.4 0.4 0.4 0.0 1.0 0.0 -0.3 0.0 0.4 0.3 0.0
yr_renovated 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0
zipcode 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -0.3 0.0 -0.3 0.0 1.0 0.3 -0.6 -0.3 0.0
lat 0.0 0.3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.3 1.0 0.0 0.0 0.0
long 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.3 0.0 0.4 0.0 -0.6 0.0 1.0 0.3 0.3
sqft_living15 0.0 0.6 0.4 0.6 0.8 0.0 0.3 0.0 0.3 0.0 0.7 0.7 0.0 0.3 0.0 -0.3 0.0 0.3 1.0 0.0
sqft_lot15 0.0 0.0 0.0 0.0 0.0 0.7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.3 0.0 1.0
In [ ]:
sns.heatmap(corr_matrix, annot = True, linewidths=0.5, cmap='coolwarm');

По тепловой карте видно что цена явно зависит от размера жилой площади (sqft_living), оценки недвижимости (grade) и возможно площади выше уровня земли (sqft_above) и Кв. метры жилой площади у 15 соседей (sqft_living15). Так как жилая площадь входит состав параметров sqft_above, sqft_living15 их можно не учитывать.

Отобразим взаимозависимости этих величин на графиках

In [ ]:
cols = ['price', 'sqft_living', 'grade']
namesax = ['Цена', 'Площадь', 'Оценка']
g = sns.PairGrid(df[cols], corner=True)
g.map(sns.scatterplot)
g.fig.suptitle("Зависимости характеристик", y=1)
Out[ ]:
Text(0.5, 1, 'Зависимости характеристик')

По графмикам можно также предположить наличие зависимостей стоимости от жилой площади и оценки

Взаимное распределение всех трех показателей показано на графике ниже.

In [ ]:
p = sns.jointplot(x=df['price'], y=df['sqft_living'], hue=df['grade']);
p.fig.suptitle('Взаимное распределение');

На графике видно что все три характеристики взаимно растут с увеличением одной из них.

Посмотрим статистические характеристики данных по цене:

In [ ]:
df['price'].describe()
Out[ ]:
count    2.161300e+04
mean     5.400881e+05
std      3.671272e+05
min      7.500000e+04
25%      3.219500e+05
50%      4.500000e+05
75%      6.450000e+05
max      7.700000e+06
Name: price, dtype: float64

Используя их разобъем стоимость домов на три блока:

  1. Низкая цена со стоимостью ниже 321950 (нижний квартиль)
  2. Средняя цена со стоимостью от 321950 до 645000
  3. Высокая цена со стоимостью выше 645000 (верхний квартиль)
In [ ]:
df.loc[df['price']<321950, 'Price_grade'] = 'Низкая цена'
df.loc[(df['price']>=321950) & ((df['price']<=645000)), 'Price_grade'] = 'Средняя цена'
df.loc[df['price']>645000, 'Price_grade'] = 'Высокая цена'
In [ ]:
df['Price_grade'].value_counts()
Out[ ]:
Price_grade
Средняя цена    10837
Низкая цена      5403
Высокая цена     5373
Name: count, dtype: int64

Построим блочную диаграмму размаха и посмотрим как распределена характеристика жилой площади по ценовым сегментам.

In [ ]:
plt.figure(figsize=(10, 6))

# sns.boxplot(x=df['sqft_living'], y=df['Price_grade'], showfliers=False)
sns.boxplot(x=df['sqft_living'], y=df['Price_grade'])
plt.xlabel('Жилая площадь')
plt.ylabel('Ценовой сегмент')
plt.title('Зависимость цены от жилой площади по сегментам');

Судя по графику, хотя прослеживается зависимость, что чем выше цена тем более высокая жилая площадь, но количество выбросов длинна "усов" говорят о том что эта характеристика не определяющая и должны быть другие характеристики влияющие на стоимость жилья.

Построим также блочную диаграмму размаха и для оценки недвижимости (grade) по ценовым сегментам.

In [ ]:
plt.figure(figsize=(10, 6))

sns.boxplot(x=df['grade'], y=df['Price_grade'])

plt.xlabel('Оценка недвижимости')
plt.ylabel('Ценовой сегмент')
plt.title('Зависимость цены от оценки недвижимости');

Также как и для жилой площади на графике видно что величина характеристики сдвигается в право с увеличением ценового сегмента, но также есть выбросы и длинные "усы", особенно для Высокоценового сегмента.

Теперь попрообуем наоборот разбить характеристику оценки на три категории: Низкое, Среднее, Высокое качество.

In [ ]:
df.loc[df['grade']<=3, 'grade_category'] = 'Низкое качество'
df.loc[(df['grade']>3) & ((df['grade']<=10)), 'grade_category'] = 'Среднее Качество'
df.loc[df['grade']>=11, 'grade_category'] = 'Высокое качество'

И построим ящик с усами для Сегементов по качеству и цены

In [ ]:
plt.figure(figsize=(10, 6))
# sns.boxplot(x=df['price'], y=df['grade_category'], showfliers=False)
sns.boxplot(x=df['price'], y=df['grade_category'])

plt.xlabel('Price')
plt.ylabel('grade_category')
plt.title('Зависимость цены от качества дизайна и архитектуры');

По графику видно, что низко оцененные дома в целом целиком поподают в область низкой стоимости. По среднему сегменту видно что есть дома на цену которых влияют другие характеристики. Но особенно это заметно по сегменту высокого качества где разброс цен очень велик.

Можно предположить что на цену домов может влиять также расположение домов в определенных зонах. Для этого построим распределение домов по координатам долготы/широты. Судя по этим параметрам наши данные относятся к городу Сиэтл и его окрестностям.

In [ ]:
min_long = -123
max_long = -122
min_lat = 47
max_lat = 48
In [ ]:
import matplotlib.image as img
seatle_map = img.imread('seatle_map3.PNG')

Построим для начала график по всем данным, расположив цену домов на цветовой шкале.

In [ ]:
plt.figure(figsize=(12,9))
sc= plt.scatter(df['long'], df['lat'], alpha=0.5, c=df['price'], cmap='plasma')
# sc=sns.scatterplot(data=df, y=df['lat'], x=df['long'], hue=df['price'])
plt.imshow(seatle_map, extent=[min_long, max_long, min_lat, max_lat], alpha=0.9)
plt.colorbar(sc)
plt.xlabel('Долгота')
plt.ylabel('Широта')
plt.title('География домов (общая)');

Уже можно видеть что наибольшая стоимость домов находится ближе к берегам на севере. Но воспользумемя разбивкой на сегменты чтобы увидеть больше закономерностей

Возьмем средний ценовой сегмент

In [ ]:
dfMeanPrice = df[df['Price_grade']=='Средняя цена']
dfMeanPrice.shape
Out[ ]:
(10837, 23)
In [ ]:
plt.figure(figsize=(12,9))
sc= plt.scatter(dfMeanPrice['long'], dfMeanPrice['lat'], alpha=0.6, c=dfMeanPrice['price'], cmap='plasma')
plt.imshow(seatle_map, extent=[min_long, max_long, min_lat, max_lat], alpha=0.9)
plt.colorbar(sc)
plt.xlabel('Долгота')
plt.ylabel('Широта')
plt.title('Георафия домов (Средний ценовой сегмент)');

На графике четко видна область с домами с более высокой ценой. Посмотрим теперь на карте распределение домов по характеристике жилой площади в этом же ценовом сегменте.

In [ ]:
plt.figure(figsize=(12,9))
sc= plt.scatter(dfMeanPrice['long'], dfMeanPrice['lat'], alpha=0.6, c=dfMeanPrice['sqft_living'], cmap='plasma')
plt.imshow(seatle_map, extent=[min_long, max_long, min_lat, max_lat], alpha=0.9)
plt.colorbar(sc)
plt.xlabel('Долгота')
plt.ylabel('Широта')
plt.title('Георафия домов /к жилой площади (Средний ценовой сегмент)');

По графику видно что в области где самая высокая цена, жилая площадь меньше. Это легко объяснить так как для среднего сегмента мы отбросили самые высокие и самые низкие данные, а размер жилой площади все же влияет на цену, поэтому для престижных райнов для домов в среднем ценовом сегменте жилая площадь ниже, иначе бы их стоимость выпала за рамки данного сегмента.

Посмотрим теперь как для среднего сегмента распределена характеристика оценки архитектуры и дизайна

In [ ]:
plt.figure(figsize=(12,9))
sc= plt.scatter(dfMeanPrice['long'], dfMeanPrice['lat'], alpha=0.6, c=dfMeanPrice['grade'], cmap='plasma')
plt.imshow(seatle_map, extent=[min_long, max_long, min_lat, max_lat], alpha=0.9)
plt.colorbar(sc)
plt.xlabel('Долгота')
plt.ylabel('Широта')
plt.title('Георафия домов /к оценке архитектуры и дизайна (Средний ценовой сегмент)');

Здесь прослеживается таже картина что и для жилой площади, пусть и менее выражено. Оценка домов в "престижных" районах ниже, благодаря чему дома и попали в средний сегмент.

Посмотрим теперь сегмент с высокой ценой

In [ ]:
dfHightPrice = df[df['Price_grade']=='Высокая цена']
dfHightPrice.shape
Out[ ]:
(5373, 23)
In [ ]:
plt.figure(figsize=(12,9))
sc= plt.scatter(dfHightPrice['long'], dfHightPrice['lat'], alpha=0.6, c=dfHightPrice['price'], cmap='plasma')
# sc=sns.scatterplot(data=df, y=df['lat'], x=df['long'], hue=df['price'])
plt.imshow(seatle_map, extent=[min_long, max_long, min_lat, max_lat], alpha=0.9)
plt.colorbar(sc)
plt.xlabel('Долгота')
plt.ylabel('Широта')
plt.title('География домов/цена (сегмент Высокая цена)');

Здесь сразу можно видеть "престижные" районы с высокой ценой, которые выделялись светлым цветом в среднем сегменте

Посиотрим и на нижний ценовой сегмент

In [ ]:
dfLowPrice = df[df['Price_grade']=='Низкая цена']
dfLowPrice.shape
Out[ ]:
(5403, 23)
In [ ]:
plt.figure(figsize=(12,9))
sc= plt.scatter(dfLowPrice['long'], dfLowPrice['lat'], alpha=0.6, c=dfLowPrice['price'], cmap='plasma')
plt.imshow(seatle_map, extent=[min_long, max_long, min_lat, max_lat], alpha=0.9)
plt.colorbar(sc)
plt.xlabel('Долгота')
plt.ylabel('Широта')
plt.title('География домов/цена (сегмент низкая цена)');

Здесь четко видно как дома с низкой ценой "обтекают" престижны район на севере на берегу и заполняет области на юге и севернее реки.

В заключении¶

Было проведено исследование как характеристики недвижимости влияют на ее стоимость. Вероятно для полноценного разбора неободимо было бы использовать регресионный анализ или другие математисеские/статистические методы.